package com.easybuilder.core.im.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.easybuilder.common.enums.WSMessageType;
import com.easybuilder.core.im.dto.SysMessageDTO;
import com.easybuilder.core.im.dto.WSMessageDTO;
import com.easybuilder.core.im.entity.SysMessage;
import com.easybuilder.core.im.netty.websocket.WebsocketContext;
import com.easybuilder.core.im.service.SignleChatService;
import com.easybuilder.core.im.service.SysMessageService;
import com.easybuilder.core.rbac.entity.SysUser;
import com.easybuilder.core.rbac.service.SysUserService;
import io.netty.channel.Channel;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import tk.mybatis.mapper.entity.Example;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;

/**
 * @author ZXS
 * @version 1.0
 * @description 单聊服务
 * @date 2022-3-24 21:26
 */
@Slf4j
@Service
public class SingleChatServiceImpl implements SignleChatService {

    @Resource
    private SysMessageService messageService;
    @Resource
    private SysUserService userService;


    /** 发送单聊消息 */
    @Override
    public void sendMessage(WSMessageDTO wsMessageDTO, Channel channel) {
        // 保存消息到数据库，状态为"未发送"，生成消息id；（用户建立连接后，首先查询数据库中是否存在为接收的消息，如果存在则通过通道发送正序发送消息）
        saveMessage(wsMessageDTO.getMessage());
        // 设置消息发送人信息
        setSenderInfo(wsMessageDTO.getMessage());
        // 根据接收人id，去通道容器里查询接收人通道
        Channel ch = WebsocketContext.getUserChannel(wsMessageDTO.getMessage().getReceiverId());
        // 接收人通道存在（在线）
        if (ch != null) {
            // 通过接收人通道发送消息（消息此时需要有id）
            WSMessageDTO result = new WSMessageDTO();
            result.setMessage(wsMessageDTO.getMessage());
            result.setType(WSMessageType.SEND_SINGLE_MESSAGE.value());
            ch.writeAndFlush(new TextWebSocketFrame(JSONObject.toJSONString(result)));
            log.info("单聊消息推送：{} -> {} : {}", wsMessageDTO.getMessage().getSenderId(), wsMessageDTO.getMessage().getReceiverId(), wsMessageDTO.getMessage());
            // 当接收人客户端收到消息后，需要立即给服务端返回确认消息，表示已经收到消息
            // 修改消息的状态为 "未读"
            // 当接收人客户端点击消息读取后，需要立即同步到服务端，修改消息状态为"已读"
        } else {
            // 接收人通道不存在（离线）
            log.info("消息接收者：{}，处于离线状态，暂不推送消息", wsMessageDTO.getMessage().getReceiverId());
        }
    }


    /** 确认收到消息，更新消息状态 */
    @Override
    public void receiveSuccess(List<Long> ids) {
        updateMessageStatus(ids, 1);
    }

    /** 客户端已读消息，更新消息状态 */
    @Override
    public void readSuccess(List<Long> ids) {
        // 批量修改消息为 ”已读“ 状态
        updateMessageStatus(ids, 2);
    }

    /** 保存消息记录 */
    private void saveMessage(SysMessageDTO messageDTO) {
        if (messageDTO != null) {
            SysMessage message = new SysMessage();
            BeanUtils.copyProperties(messageDTO, message);
            message.setMessageStatus(0);
            message.setDropStatus(0);
            message.setMessageType(0);
            message.setCreateTime(new Date());
            messageService.insertSelective(message);
            BeanUtils.copyProperties(message, messageDTO);
        }
    }

    /** 更新消息状态 */
    private void updateMessageStatus(List<Long> ids, Integer messageStatus) {
        // 批量修改消息为“未读” 状态
        Example example = new Example(SysMessage.class);
        example.createCriteria().andIn("id", ids);
        SysMessage sysMessage = new SysMessage();
        sysMessage.setMessageStatus(messageStatus);
        int update = messageService.updateByExampleSelective(sysMessage, example);
        log.info("更新消息状态，影响条数：{}", update);
    }

    /** 设置发送人信息 */
    private void setSenderInfo(SysMessageDTO message) {
        if (message != null) {
            Long senderId = message.getSenderId();
            SysUser sender = userService.getUserById(senderId);
            if (sender != null) {
                message.setSenderNickname(sender.getNickname());
                message.setSenderImg(sender.getImg());
            }
        }
    }
}
